		TITLE	PACKSEGS - Copyright (c) 1994 SLR Systems

		INCLUDE	MACROS
		INCLUDE	SEGMENTS
		INCLUDE	GROUPS
if	fg_segm
		INCLUDE	SEGMSYMS
endif

		PUBLIC	PACK_SEGMENTS


		.DATA

		EXTERNDEF	SEGMENT_COUNT:DWORD,ZERO_LENGTH_SEGMENTS:DWORD,PACKCODE:DWORD,PACKDATA:DWORD,PACK_DEFAULT_SIZE:DWORD
		EXTERNDEF	FIRST_SEGMENT_GINDEX:DWORD,FIRST_GROUP_GINDEX:DWORD,APPLOADER_SEGMENT_GINDEX:DWORD
		EXTERNDEF	SEGMENT_TABLE_PTR:DWORD

		EXTERNDEF	SEGMENT_GARRAY:STD_PTR_S,GROUP_GARRAY:STD_PTR_S,SEGMENT_TABLE:QWORD,SEGMOD_GARRAY:STD_PTR_S


		.CODE	MIDDLE_TEXT

		EXTERNDEF	WARN_RET:PROC,_err_abort:proc,DO_ECX_ALIGN:PROC,ERR_ASCIZ_RET:PROC

		EXTERNDEF	CODEPACK_ERR:ABS,DATAPACK_ERR:ABS,TOO_MANY_SEGS_ERR:ABS,GRP_TOO_BIG_ERR:ABS


PACK_SEGMENTS	PROC
		;
		;IF PACKCODE SET, DO PACKCODE
		;
		BITT	PACKCODE_FLAG
		JZ	NO_PACKCODE
		CALL	DO_PACKCODE
NO_PACKCODE:
		;
		;IF PACKDATA SET, DO PACKDATA
		;
NP_1:
		BITT	PACKDATA_FLAG
		JZ	NO_PACKDATA
		CALL	DO_PACKDATA
NO_PACKDATA:

if	fg_segm
if	fg_norm_exe
		BITT	OUTPUT_SEGMENTED
		JZ	PACKING_DONE1
endif
		;
		;IF SEGMENTS >254, TRY SETTING PACKCODE OR PACKDATA AND GO
		;AGAIN... WARN IF YOU DO IT...
		;
		MOV	EAX,SEGMENT_COUNT
		SUB	EAX,ZERO_LENGTH_SEGMENTS

		CMP	EAX,254
		JBE	PACKING_DONE

		BITT	PACKCODE_FLAG
		JNZ	CODE_PACKED

		SETT	PACKCODE_FLAG

		MOV	EAX,PACK_DEFAULT_SIZE
		MOV	PACKCODE,EAX

		MOV	AL,CODEPACK_ERR
		CALL	WARN_RET

		JMP	PACK_SEGMENTS

CODE_PACKED:
		BITT	PACKDATA_FLAG
		JNZ	DATA_PACKED

		SETT	PACKDATA_FLAG
		MOV	EAX,PACK_DEFAULT_SIZE
		MOV	PACKDATA,EAX
		MOV	AL,DATAPACK_ERR
		CALL	WARN_RET
		JMP	NP_1


DATA_PACKED::
		;
		;IF SEGMENTS >254, ITS A FATAL ERROR
		;
		MOV	AL,TOO_MANY_SEGS_ERR
		push	EAX
		call	_err_abort

endif

PACKING_DONE:
		CALL	SIZE_PROT_SEGMENTS	;DEFINE SEGMENT_TABLE STUFF,
						;GETTING RID OF 0-LENGTH ITEMS
PACKING_DONE1:
		CALL	SIZE_GROUPS
		RET

PACK_SEGMENTS	ENDP


DO_PACKCODE	PROC	NEAR
		;
		;COMBINE AS MANY CODE SEGMENTS AS POSSIBLE INTO AS FEW
		;
		;
		;SET UP FOR CALLING PACK_REAL
		;
		MOV	EBX,PACKCODE
		MOV	EDX,MASK SEG_CLASS_IS_CODE	;PACK CODE SEGS
if	fg_prot AND fg_norm_exe
		BITT	OUTPUT_SEGMENTED
		JNZ	DO_PACK_PROT
		JMP	DO_PACK_REAL
else if fg_norm_exe
		JMP	DO_PACK_REAL
endif

PACK_PROT_STRUCT	STRUC

PACKSIZE_BP		DD	?
PACKTYPE_BP		DB	?
			DB	?
			DW	?
PACKP_TEMP_WORD_BP	DD	?

PACK_PROT_STRUCT	ENDS

PACKSIZE		EQU	([EBP-SIZE PACK_PROT_STRUCT].PACKSIZE_BP)
PACKTYPE		EQU	([EBP-SIZE PACK_PROT_STRUCT].PACKTYPE_BP)
PACKP_TEMP_WORD		EQU	([EBP-SIZE PACK_PROT_STRUCT].PACKP_TEMP_WORD_BP)

if	fg_prot

DO_PACK_PROT::
		PUSH	EBP
		MOV	EBP,ESP
		ASSUME	EBP:PTR PACK_PROT_STRUCT

		SUB	ESP,SIZE PACK_PROT_STRUCT

		MOV	ESI,FIRST_SEGMENT_GINDEX
		XOR	EDI,EDI			;AMOUNT WE ARE ADJUSTING SEGMENT #'S

		MOV	PACKSIZE,EBX
		MOV	PACKTYPE,DL

		JMP	TEST_OUTER_SEG		;HAVEN'T FOUND ONE TO PACK YET

OUTER_SEG_LOOP:
		;
		;LOOKING FOR A FEW GOOD SEGS
		;
		MOV	EAX,APPLOADER_SEGMENT_GINDEX
		MOV	ECX,ESI
		CONVERT	ESI,ESI,SEGMENT_GARRAY
		ASSUME	ESI:PTR SEGMENT_STRUCT

		CMP	EAX,ECX
		JZ	NEXT_OUTER_SEG

		MOV	AL,[ESI]._SEG_TYPE
		MOV	EDX,[ESI]._SEG_OS2_NUMBER

		TEST	AL,MASK SEG_CV_TYPES1 + MASK SEG_CV_SYMBOLS1	;DONE IF CODEVIEW
		JNZ	DONE

		AND	AL,MASK SEG_CLASS_IS_CODE
		SUB	EDX,EDI				;ADJUST SEGMENT #

		MOV	AH,PACKTYPE
		MOV	[ESI]._SEG_OS2_NUMBER,EDX

		XOR	AL,AH
		JNZ	NEXT_OUTER_SEG

		MOV	EAX,[ESI]._SEG_GROUP_GINDEX

		TEST	EAX,EAX
		JZ	NEW_SEG
NEXT_OUTER_SEG:
		MOV	ESI,[ESI]._SEG_NEXT_SEG_GINDEX
TEST_OUTER_SEG:
		TEST	ESI,ESI
		JNZ	OUTER_SEG_LOOP
DONE:
		MOV	ESP,EBP

		POP	EBP

		RET

NEW_SEG:
		;
		;FOUND CORRECT CODE VS DATA TYPE, NON-GROUPED
		;
SAME_SEG:
		;
		;SET DX:CX TO SEGMENT SIZE SO FAR
		;
		MOV	ECX,[ESI]._SEG_OFFSET
		MOV	EAX,[ESI]._SEG_LEN

		ADD	ECX,EAX
		MOV	EAX,PACKSIZE

		CMP	ECX,EAX
		JAE	NEXT_OUTER_SEG		;>= PACKSIZE, CANNOT COMBINE

		MOV	EBX,[ESI]._SEG_OS2_FLAGS
		MOV	ESI,[ESI]._SEG_NEXT_SEG_GINDEX
		;
		;SEE IF NEXT SEGMENT CAN COMBINE WITH IT
		;
		TEST	ESI,ESI
		JZ	DONE

		MOV	PACKP_TEMP_WORD,ESI
		CONVERT	ESI,ESI,SEGMENT_GARRAY

		MOV	AL,[ESI]._SEG_TYPE
		MOV	EDX,[ESI]._SEG_OS2_NUMBER

		TEST	AL,MASK SEG_CV_TYPES1 + MASK SEG_CV_SYMBOLS1
		JNZ	DONE

		AND	AL,MASK SEG_CLASS_IS_CODE
		SUB	EDX,EDI				;ADJUST SEGMENT #

		MOV	AH,PACKTYPE
		MOV	[ESI]._SEG_OS2_NUMBER,EDX

		XOR	AL,AH
		JNZ	NEXT_OUTER_SEG		;WRONG CODE VS DATA TYPE, TRY NEXT SEGMENT

		MOV	EAX,[ESI]._SEG_GROUP_GINDEX
		MOV	EDX,[ESI]._SEG_OS2_FLAGS

		TEST	EAX,EAX
		JNZ	NEXT_OUTER_SEG		;CANNOT COMBINE GROUPED SEGMENTS FOR NOW...

		CMP	EDX,EBX
		JNZ	NEW_SEG			;CANNOT COMBINE, BUT CORRECT TYPE...
		;
		;ALIGN TO MAX FOR THIS SEGMENT
		;
		MOV	AL,[ESI]._SEG_MAX_ALIGN
		CALL	DO_ECX_ALIGN

		MOV	EDX,[ESI]._SEG_LEN
		MOV	EAX,PACKSIZE

		ADD	ECX,EDX

		CMP	EAX,ECX
		JC	NEW_SEG			;>LIMIT, TRY AGAIN...
		;
		;!!!!!	WE JUST SAVED A SELECTOR... !!!!!
		;
		;UPDATE SELECTOR #'S
		;
		MOV	EDX,[ESI]._SEG_OS2_NUMBER
		INC	EDI			;WE'LL BE SUBTRACTING ONE MORE

		DEC	EDX
		MOV	EAX,PACKP_TEMP_WORD

		MOV	[ESI]._SEG_OS2_NUMBER,EDX
		CALL	PACK_SEGMENT

		MOV	ESI,PACKP_TEMP_WORD
		CONVERT	ESI,ESI,SEGMENT_GARRAY
		JMP	SAME_SEG

endif

DO_PACKCODE	ENDP


if	fg_prot

PACK_SEGMENT	PROC	NEAR
		;
		;
		;
		PUSH	EDI				;SAVE SEGS PACKED SO FAR
		MOV	EDI,EAX				;SAVE SEGMENT_GINDEX

		MOV	EAX,SEGMENT_COUNT
		MOV	EDX,[ESI]._SEG_LEN

		DEC	EAX
		SUB	ECX,EDX

		TEST	EDX,EDX
		JNZ	L0$
		DEC	ZERO_LENGTH_SEGMENTS
L0$:
		MOV	SEGMENT_COUNT,EAX
		MOV	[ESI]._SEG_OFFSET,ECX

		MOV	ESI,[ESI]._SEG_FIRST_SEGMOD_GINDEX
		JMP	TEST_SM

L1$:
		CONVERT	ESI,ESI,SEGMOD_GARRAY
		ASSUME	ESI:PTR SEGMOD_STRUCT

		MOV	EAX,[ESI]._SM_BASE_SEG_GINDEX
		MOV	EDX,[ESI]._SM_START

		CMP	EAX,EDI
		JNZ	L9$

		MOV	EAX,[ESI]._SM_LEN
		ADD	EDX,ECX

		ADD	EAX,ECX
		MOV	[ESI]._SM_START,EDX

		MOV	[ESI]._SM_LEN,EAX
		MOV	ESI,[ESI]._SM_NEXT_SEGMOD_GINDEX
TEST_SM:
		TEST	ESI,ESI
		JNZ	L1$
L9$:
		POP	EDI
		RET

PACK_SEGMENT	ENDP

endif


DO_PACKDATA	PROC	NEAR
		;
		;COMBINE AS MANY DATA SEGMENTS AS POSSIBLE INTO AS FEW
		;
		MOV	EBX,PACKDATA
		XOR	EDX,EDX			;USE DATA SEGMENTS
if	fg_prot
if	fg_norm_exe
		BITT	OUTPUT_SEGMENTED
		JNZ	DO_PACK_PROT
else
		JMP	DO_PACK_PROT
endif
endif

DO_PACKDATA	ENDP


if	fg_norm_exe

DO_PACK_REAL	PROC	NEAR
		;
		;EDX IS FLAG TO CHECK (CODE VS DATA)
		;EBX IS PACKCODE LIMIT
		;
		;SCAN LIST OF SEGS, STICKING ANY NON-GROUPED ITEMS INTO
		;DUMMY GROUPS, MARK THEM 'PACKED'
		;
		PUSH	EBP
		MOV	EBP,ESP

		SUB	ESP,SIZE PACK_PROT_STRUCT
		MOV	ESI,FIRST_SEGMENT_GINDEX

		MOV	PACKSIZE,EBX
		MOV	PACKTYPE,DL

		JMP	TEST_SEG


SEG_LOOP:
		MOV	ECX,ESI
		CONVERT	ESI,ESI,SEGMENT_GARRAY
		ASSUME	ESI:PTR SEGMENT_STRUCT

		CALL	CHECK_REAL_PACKABILITY
		JZ	NEW_SEG
NEXT_SEG:
		MOV	ESI,[ESI]._SEG_NEXT_SEG_GINDEX
TEST_SEG:
		TEST	ESI,ESI
		JNZ	SEG_LOOP
DONE:
		MOV	ESP,EBP

		POP	EBP

		RET


NEW_SEG:
		;
		;FOUND CORRECT CODE VS DATA, NON-GROUPED
		;
SAME_SEG:
		MOV	ECX,[ESI]._SEG_OFFSET
		MOV	EDX,[ESI]._SEG_LEN

		ADD	ECX,EDX
		MOV	EDI,[ESI]._SEG_FRAME

		SUB	ECX,EDI
		MOV	EAX,PACKSIZE

		CMP	ECX,EAX
		JA	NEXT_SEG
		;
		;SEE IF NEXT SEGMENT CAN COMBINE WITH IT
		;
		MOV	ESI,[ESI]._SEG_NEXT_SEG_GINDEX

		TEST	ESI,ESI
		JZ	DONE
		CONVERT	ESI,ESI,SEGMENT_GARRAY
		ASSUME	ESI:PTR SEGMENT_STRUCT

		CALL	CHECK_REAL_PACKABILITY
		JNZ	NEW_SEG

		MOV	ECX,[ESI]._SEG_OFFSET
		MOV	EDX,[ESI]._SEG_LEN

		ADD	ECX,EDX
		MOV	EAX,PACKSIZE

		SUB	ECX,EDI

		CMP	EAX,ECX
		JC	NEW_SEG			;>LIMIT, TRY AGAIN...

		MOV	[ESI]._SEG_FRAME,EDI	;SET NEW FRAME FOR THAT SEGMENT
		JMP	SAME_SEG

DO_PACK_REAL	ENDP


CHECK_REAL_PACKABILITY	PROC	NEAR
		;
		;
		;
		ASSUME	ESI:PTR SEGMENT_STRUCT

		MOV	AL,[ESI]._SEG_TYPE
		MOV	BL,PACKTYPE

		TEST	AL,MASK SEG_CV_TYPES1 + MASK SEG_CV_SYMBOLS1	;CV INFO AT END, DONE
		JNZ	L5$

		XOR	AL,BL
		MOV	EBX,[ESI]._SEG_GROUP_GINDEX

		AND	AL,MASK SEG_CLASS_IS_CODE		;IS THIS CORRECT CODE VS DATA?
		JNZ	L5$					;WRONG TYPE, SKIP
if	any_overlays
		BITT	DOING_OVERLAYS
		JZ	4$
		;
		;MAKE SURE THIS ISN'T PART OF OVERLAY LOADER
		;
		MOV	AX,[SI]._SEG_CLASS_GINDEX
		CMP	SLR_CODE_CLASS_GINDEX,AX
		JZ	#FAIL
		CMP	SLR_SCODE_CLASS_GINDEX,AX
		JZ	#FAIL
		;
		;MAKE SURE THIS GUY IS BASED IN ROOT SECTION
		;
		MOV	AX,[SI]._SEG_OFFSET.HW
		CMP	VECTOR_TABLE_ADDRESS.HW,AX
		JB	#FAIL
		JA	4$
		MOV	AX,[SI]._SEG_OFFSET.LW
		CMP	VECTOR_TABLE_ADDRESS.LW,AX
		JB	#FAIL
4$:
endif
		;
		;CORRECT TYPE, DO WE MARK IT PACKED? YES FOR NOW
		;
		TEST	EBX,EBX
L5$:
		RET

CHECK_REAL_PACKABILITY	ENDP

endif

if	fg_prot

SIZE_PROT_SEGMENTS	PROC	NEAR
		;
		;GO THROUGH LIST OF SEGMENTS, DEFINING FLAGS AND SIZES IN
		;SEGMENT TABLE
		;
		;UNCOUNT ANY ZERO-LENGTH SEGMENTS
		;
		MOV	EDI,OFF SEGMENT_TABLE		;FIRST SEGMENT...
		ASSUME	EDI:PTR SEGTBL_STRUCT
		MOV	ESI,FIRST_SEGMENT_GINDEX

		MOV	SEGMENT_TABLE_PTR,EDI
		MOV	EDX,1			;LAST SEGMENT #

		LEA	EDI,[EDI + SIZE SEGTBL_STRUCT]
		MOV	ECX,EDX

		TEST	ESI,ESI
		JZ	L8$
SEG_LOOP:
		CONVERT	ESI,ESI,SEGMENT_GARRAY
		ASSUME	ESI:PTR SEGMENT_STRUCT

		MOV	AL,[ESI]._SEG_TYPE
		MOV	EBX,[ESI]._SEG_OS2_NUMBER

		TEST	AL,MASK SEG_CV_TYPES1 + MASK SEG_CV_SYMBOLS1
		JNZ	L8$

		CMP	EBX,ECX 	;SAME AS LAST SEGMENT #?
		JZ	L2$
		;
		;NEW SEGMENT, WAS LAST ONE ZERO LENGTH?
		;
		MOV	EAX,[EDI]._SEGTBL_LSIZE
		MOV	ECX,[ESI]._SEG_OS2_NUMBER

		TEST	EAX,EAX
		JZ	L1$		;YES, DON'T UPDATE SEGMENT #...
L0$:
		ADD	EDI,SIZE SEGTBL_STRUCT
		INC	EDX
L1$:
		;
		;STORE FLAGS, SIZE...
		;
L2$:					;here so flags get set for segment 1
		;
		;UPDATE ACTUAL SEGMENT #
		;
		MOV	EAX,[ESI]._SEG_OS2_FLAGS
		MOV	[ESI]._SEG_OS2_NUMBER,EDX

		MOV	EBX,[ESI]._SEG_OFFSET
		MOV	[EDI]._SEGTBL_FLAGS,EAX
		;
		;UPDATE SEGMENT LENGTH
		;
		MOV	EAX,[ESI]._SEG_LEN
		MOV	ESI,[ESI]._SEG_NEXT_SEG_GINDEX

		ADD	EAX,EBX
		TEST	ESI,ESI

		MOV	[EDI]._SEGTBL_LSIZE,EAX
		JNZ	SEG_LOOP
L8$:
		;
		;UNDO LAST SEGMENT IF ZERO LENGTH
		;
		MOV	EAX,[EDI]._SEGTBL_LSIZE

		OR	EAX,EAX
		JNZ	L9$
		;
		;PACK ALL SEGMENTS OF # DX ONTO END OF LAST SEGMENT # DX-1
		;
		DEC	EDX
		JZ	L9$			;ZERO SEGMENTS

		CALL	PACK_LAST_SEGMENT
L9$:
		MOV	SEGMENT_COUNT,EDX
		CMP	EDX,254
		JA	L91$
		RET

L91$:
		JMP	DATA_PACKED

SIZE_PROT_SEGMENTS	ENDP


PACK_LAST_SEGMENT	PROC	NEAR
		;
		;EDX IS SEGMENT TO PACK ALL EDX+1 SEGMENTS INTO
		;
		MOV	ESI,FIRST_SEGMENT_GINDEX	;SO, SCAN FOR SEGMENT DX
		SUB	EDI,SIZE SEGTBL_STRUCT

		MOV	ECX,EAX
L1$:
		MOV	EBX,ECX
		MOV	ECX,ESI
		CONVERT	ESI,ESI,SEGMENT_GARRAY
		ASSUME	ESI:PTR SEGMENT_STRUCT

		MOV	EAX,[ESI]._SEG_OS2_NUMBER
		MOV	ESI,[ESI]._SEG_NEXT_SEG_GINDEX

		CMP	EAX,EDX
		JA	L5$

		TEST	ESI,ESI
		JNZ	L1$

		JMP	L9$

L5$:
		MOV	EAX,ESI

		CONVERT	ESI,ECX,SEGMENT_GARRAY
		;
		;BX IS LAST DX SEGMENT, USE IT'S ENDING OFFSET AS PLACE TO PACK REST OF SEGMENTS
		;CX IS FIRST SEGMENT NEEDING NEW OFFSET
		;
		;THIS MAY BE MULTIPLE SEGMENTS
		;
		MOV	ECX,[EDI]._SEGTBL_LSIZE		;LOGICAL SIZE
L6$:
		PUSH	EAX			;SAVE NEXT SEGMENT
		MOV	EBX,[ESI]._SEG_FIRST_SEGMOD_GINDEX
		MOV	[ESI]._SEG_OFFSET,ECX
		MOV	[ESI]._SEG_OS2_NUMBER,EDX
L7$:
		CONVERT	EBX,EBX,SEGMOD_GARRAY
		ASSUME	EBX:PTR SEGMOD_STRUCT

		MOV	[EBX]._SM_START,ECX
		MOV	[EBX]._SM_LEN,ECX

		MOV	EBX,[EBX]._SM_NEXT_SEGMOD_GINDEX

		TEST	EBX,EBX
		JNZ	L7$

		POP	ESI			;NEXT SEGMENT #

		TEST	ESI,ESI
		JZ	L8$
		CONVERT	ESI,ESI,SEGMENT_GARRAY
		ASSUME	ESI:PTR SEGMENT_STRUCT

		MOV	BL,[ESI]._SEG_TYPE
		MOV	EAX,[ESI]._SEG_NEXT_SEG_GINDEX

		AND	BL,MASK SEG_CV_TYPES1 + MASK SEG_CV_SYMBOLS1	;DONE IF CODEVIEW
		JZ	L6$
L8$:
L9$:
		RET

PACK_LAST_SEGMENT	ENDP

endif


SIZE_GROUPS	PROC
		;
		;FOR SEGM, SET OS2_NUMBER TOO
		;
		MOV	ESI,FIRST_GROUP_GINDEX
		JMP	TEST_GROUP

GROUP_LOOP:
		CONVERT	ESI,ESI,GROUP_GARRAY
		ASSUME	ESI:PTR GROUP_STRUCT

		MOV	EDI,[ESI]._G_FIRST_SEG_GINDEX
		MOV	EDX,[ESI]._G_LEN

		TEST	EDI,EDI
		JZ	L4$

		MOV	EAX,[ESI]._G_OFFSET
		MOV	ECX,EDX

		SUB	EDX,EAX
		GETT	AL,OUTPUT_SEGMENTED

		MOV	[ESI]._G_LEN,EDX
		GETT	DL,OUTPUT_PE

		OR	AL,DL
		JNZ	L1$

		SUB	ECX,[ESI]._G_FRAME
		JMP	L2$

L1$:
		CONVERT	EDI,EDI,SEGMENT_GARRAY
		ASSUME	EDI:PTR SEGMENT_STRUCT

		MOV	EAX,[EDI]._SEG_OS2_NUMBER
		MOV	[ESI]._G_OS2_NUMBER,EAX
L2$:
		CMP	ECX,64K
		JA	MTB
L4$:
		MOV	ESI,[ESI]._G_NEXT_GROUP_GINDEX
TEST_GROUP:
		TEST	ESI,ESI
		JNZ	GROUP_LOOP
L9$:
		RET



MTB:
		TEST	[ESI]._G_TYPE1,MASK GROUP_IS_USE32
		JNZ	L4$
		LEA	ECX,[ESI]._G_TEXT
		MOV	AL,GRP_TOO_BIG_ERR
		CALL	ERR_ASCIZ_RET
		JMP	L4$

SIZE_GROUPS	ENDP


		END

